#include "SketcherHelper.h"
#include <math.h>
#include <vector>
#include <direct.h>
#include <stdio.h>
#include "GeometryHelper.h"

SketcherHelper* SketcherHelper::instance = 0;
void SketcherHelper::initializeInstance(int width, int height, Color* backColor, Color* borderColor){
	atexit(SDL_Quit );
	if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ){
		cout << "Video initialization failed: %s\n"<<SDL_GetError( ) <<endl;
	}

	this->screen= SDL_SetVideoMode(width,height,COLOR_DEEP,SDL_HWSURFACE);
	if ( this->screen == NULL){
		cout <<  "error al inicializar el modo grafico: %s\n"<< SDL_GetError()<<endl;
	}


	if(this->background==NULL){
		SDL_FreeSurface(this->background);
	}
	SDL_WM_SetCaption("Zuma, the game","Zuma");
	
	Position p;
	p.setPixel(0,height/2);
	Uint32 rmask = 0xff000000;
	Uint32 gmask = 0x00ff0000;
	Uint32 bmask = 0x0000ff00;
	Uint32 amask = 0x00000000;
	
	if(this->background==NULL){
		SDL_FreeSurface(this->background);
	}
	this->background=SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,this->screen->format->BitsPerPixel,rmask,gmask,bmask,amask);

	drawSquare(&p,width,height,0,backColor,borderColor);

}

void SketcherHelper::showGameOver(int width, int height, Texture* texture, Color* borderColor){
	SDL_Surface* loading=SDL_LoadBMP("imagenes/gameover.bmp");
	SDL_Rect rec;
	rec.w=width;
	rec.h=height;
	rec.x=0;
	rec.y=0;
	SDL_BlitSurface(this->scaleSurface(loading,width,height),&rec,this->screen,&rec);
	this->show();	
}

void SketcherHelper::initializeInstance(int width, int height, Texture* texture, Color* borderColor){
	atexit(SDL_Quit );
	if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ){
		cout << "Video initialization failed: %s\n"<<SDL_GetError( ) <<endl;
	}
	this->screen= SDL_SetVideoMode(width,height,COLOR_DEEP,SDL_HWSURFACE);
	if ( this->screen==NULL){
		cout <<  "error al inicializar el modo grafico: %s\n"<< SDL_GetError()<<endl;
	}
	//Initialize SDL_ttf
	if (TTF_Init()==-1)
	{
		cout <<  "error al inicializar el modo grafico: %s\n"<< SDL_GetError()<<endl;
	}
	/*---------------------------Get The font And Set Color---------------------*/	
	
	char cCurrentPath[200];
	stringstream ss;
	getcwd(cCurrentPath,sizeof(cCurrentPath));	
	ss<<cCurrentPath << "\\" <<"AURORABC.TTF";	
	//font=TTF_OpenFont(ss.str().c_str(),27.5);
	font=TTF_OpenFont("AURORABC.TTF",27.5);
	if (font==NULL)
		return;
	this->aux_rect=new SDL_Rect();
	this->text_x=0;
	this->text_y=0;
	/*-----------------------------End font initialization-----------------------*/
	SDL_WM_SetCaption("Zuma, the game","Zuma");
	
	SDL_Surface* loading=SDL_LoadBMP("imagenes/loading.bmp");
	SDL_Rect rec;
	rec.w=width;
	rec.h=height;
	rec.x=0;
	rec.y=0;
	SDL_BlitSurface(this->scaleSurface(loading,width,height),&rec,this->screen,&rec);
	this->show();
	
	SDL_Rect dest;
	dest.w = width;
	dest.h = height;
	dest.x = 0;
	dest.y = 0;
	
	SDL_Surface *imagen;

	if(images[texture->getPath()]){
		imagen = images[texture->getPath().c_str()];
	}else{
		imagen = SDL_LoadBMP(texture->getPath().c_str());
		images[texture->getPath()] = imagen;
	}
	
	SDL_Surface * cuadrado=scaleSurface(imagen,width,height);
	if(borderColor != NULL){
		for(int i = 0 ; i < width; i++){
			Position p;
			p.setPixel(i,0);
			drawPixel(cuadrado,p,borderColor);
			p.setPixel(i,cuadrado->h-1);
			drawPixel(cuadrado,p,borderColor);
		}
		for(int i = 0 ; i < height; i++){
			Position p;
			p.setPixel(0,i);
			drawPixel(cuadrado,p,borderColor);
			p.setPixel(cuadrado->w-1,i);
			drawPixel(cuadrado,p,borderColor);
		}
	}
	if(this->background == NULL){
		SDL_FreeSurface(this->background);
	}
	Uint32 rmask = 0xff000000;
	Uint32 gmask = 0x00ff0000;
	Uint32 bmask = 0x0000ff00;
	Uint32 amask = 0x00000000;
	this->background=SDL_CreateRGBSurface(SDL_SWSURFACE,this->screen->w,this->screen->h,this->screen->format->BitsPerPixel,rmask,gmask,bmask,amask);

	SDL_BlitSurface(cuadrado,NULL,this->screen,&dest);
}

SketcherHelper* SketcherHelper::getInstance(){
	if(!instance){
		instance= new SketcherHelper();
	}
	return instance;
}
void SketcherHelper::endInitialicing(){
	for(int i = 0; i < this->background->w; i++){
		for(int j = 0; j < this->background->h; j++){
			Position p;
			p.setPixel(i,j);
			drawPixel(background,p,readPixel(this->screen,p));
		}
	}
}
void SketcherHelper::clearLine(Position* fromPosition,Position* toPosition){
	int b;
	float m;
	Position * aux = new Position();
	int minPixelY = min(fromPosition->getPixelY(), toPosition->getPixelY());
	int maxPixelY = max(fromPosition->getPixelY(), toPosition->getPixelY());
	int minPixelX = min(fromPosition->getPixelX(), toPosition->getPixelX());
	int maxPixelX = max(fromPosition->getPixelX(), toPosition->getPixelX());

	Position * leftPosition = fromPosition->getPixelX() == minPixelX ? fromPosition : toPosition;
	b = leftPosition->getPixelY(); // La ordenada al origen se considera corresponde al menor x.
	m = tan(GeometryHelper::getInstance()->getAngle(fromPosition,toPosition));

	if(fromPosition->getPixelX() == toPosition->getPixelX()) {
		for(int i = minPixelY ; i <= maxPixelY ; i++) {
			aux->setPixel(fromPosition->getPixelX(),i);
			if((aux->getPixelX()>=0&&aux->getPixelY()>=0&&aux->getPixelX()<this->screen->w&&aux->getPixelY()<this->screen->h))
				drawPixel(this->screen,*aux,readPixel(this->background,*aux));
		}
	}else {
		int y, x = minPixelX;
		int lastY = GeometryHelper::getInstance()->fx(x-minPixelX,m,b);
		for(x; x <= maxPixelX; x++) {
			y = GeometryHelper::getInstance()->fx(x-minPixelX,m,b);
			for(int yCorrect = min(y,lastY); yCorrect < max(y,lastY);yCorrect++ ) {
				aux->setPixel(x,yCorrect);
				if((aux->getPixelX()>=0&&aux->getPixelY()>=0&&aux->getPixelX()<this->screen->w&&aux->getPixelY()<this->screen->h))
					drawPixel(this->screen,*aux,readPixel(this->background,*aux));
			}
			aux->setPixel(x,y);
			if((aux->getPixelX()>=0&&aux->getPixelY()>=0&&aux->getPixelX()<this->screen->w&&aux->getPixelY()<this->screen->h))
				drawPixel(this->screen,*aux,readPixel(this->background,*aux));
			lastY = y;
		}
	}
	delete aux;
}

inline void SketcherHelper::clearBackground(Position *position,int width,int height){
	register int endX = position->getPixelX()+2 + width;
	register int endY = position->getPixelY()+2+height;
	for(register int i = position->getPixelX()-1; i < endX; i++){
		for(register int j = position->getPixelY()-1; j < endY; j++){
			Position p;
			p.setPixel(i,j);
			if( (p.getPixelX() >=0 && p.getPixelY() >=0) && 
					(p.getPixelX() < this->screen->w) && 
					(p.getPixelY() < this->screen->h) ){
				drawPixel(this->screen,p,readPixel(this->background,p));
			}
		}
	}
}
SDL_Surface* SketcherHelper::createCircleSurface( int radiuos, Texture* backTexture, Color* borderColor){
	SDL_Surface* surface;
    Uint32 rmask = 0xff000000;
	Uint32 gmask = 0x00ff0000;
	Uint32 bmask = 0x0000ff00;
	Uint32 amask = 0x00000000;
	SDL_Surface *border=SDL_CreateRGBSurface(SDL_SWSURFACE,1,1,COLOR_DEEP,amask,amask,amask,amask);

	Position pCeroBorder;
	pCeroBorder.setPixel(0,0);
	
	double margin=radiuos*0.04;
	if(borderColor==NULL){
		radiuos=radiuos+margin;
	}else{
		drawPixel(border,pCeroBorder,borderColor);
	}
	
	SDL_Surface *imagen;

	if(images[backTexture->getPath()]){
		imagen = images[backTexture->getPath().c_str()];
	}else{
		imagen = SDL_LoadBMP(backTexture->getPath().c_str());
		images[backTexture->getPath()] = imagen;
	}

	int width;
	int height;
	Position initial;
	if(imagen->w<imagen->h){
		width=2*radiuos;
		height=width*imagen->h/imagen->w;
		initial.setPixel(0,(height-2*radiuos)/2);
	}else{
		height=2*radiuos;
		width=height*imagen->w/imagen->h;
		initial.setPixel((width-2*radiuos)/2,0);
	}

	 surface=scaleSurface(imagen,width,height);	
	 SDL_SetColorKey(surface,SDL_SRCCOLORKEY|SDL_RLEACCEL,SDL_MapRGB(surface->format,255,255,255));
	 return surface;
}
void SketcherHelper::drawCircleFromSurface(Position* center, int radiuos, SDL_Surface* surface){
	
	SDL_Rect rect;

	rect.w=surface->w;
	rect.h=surface->h;
	rect.x=center->getPixelX()-radiuos;
	rect.y=center->getPixelY()-radiuos;
	SDL_BlitSurface(surface,NULL,this->screen,&rect);
	/*Position pCero;
	Position initial;
	if(surface->w < surface->h){
		initial.setPixel(0,(surface->h - 2*radiuos)/2);
	}else{
		initial.setPixel((surface->w - 2*radiuos)/2,0);
	}
	for(register int i=0;i<2*radiuos;i++){
		for(register int j=0;j<2*radiuos;j++){
			Position p;
			p.setPixel(i+(center->getPixelX()-radiuos),j+(center->getPixelY()-radiuos));
			double longitud= calcDist(p,*center);
			pCero.setPixel(initial.getPixelX()+i,initial.getPixelY()+j);
			if(longitud<=radiuos &&(	p.getPixelX()>=0 && p.getPixelY()>=0&&p.getPixelX()<this->screen->w&&p.getPixelY()<this->screen->h)&&
				pCero.getPixelX()>=0&&pCero.getPixelY()>=0
				&&pCero.getPixelX()<surface->w&&pCero.getPixelY()<surface->h){
					drawPixel(this->screen,p,readPixel(surface,pCero));	
			}			
		}
	}*/
}

SDL_Surface* SketcherHelper::createCircleSurface( int radiuos, Color* backColor, Color* borderColor)
{
	SDL_Surface* surface;
	Uint32 rmask = 0xff000000;
	Uint32 gmask = 0x00ff0000;
	Uint32 bmask = 0x0000ff00;
	Uint32 amask = 0x00000000;
	double margin = radiuos * 0.04;
	SDL_Surface *back = SDL_CreateRGBSurface(SDL_SWSURFACE,1,1,COLOR_DEEP,amask,amask,amask,amask);
	SDL_Surface *border = SDL_CreateRGBSurface(SDL_SWSURFACE,1,1,COLOR_DEEP,amask,amask,amask,amask);
	surface = SDL_CreateRGBSurface(SDL_SWSURFACE,2*(radiuos+margin),2*(radiuos+margin),this->screen->format->BitsPerPixel,amask,amask,amask,amask);
	SDL_SetColorKey(surface,SDL_SRCCOLORKEY|SDL_RLEACCEL,SDL_MapRGB(this->screen->format,0,0,0));
	Position pCero;
	pCero.setPixel(0,0);
	drawPixel(back,pCero,backColor);
	if(borderColor != NULL){
		drawPixel(border,pCero,borderColor);
	}
	Position * center = new Position(radiuos,radiuos);
	for(int i = 0; i<2*(radiuos+margin);i++){
		for(int j = 0; j<2*(radiuos+margin);j++){
			Position p;
			p.setPixel(i,j);
			double longitud= calcDist(p,*center);
			if(radiuos+margin>=longitud && radiuos-margin<=longitud){
				if(borderColor!=NULL&&p.getPixelX()>=0&&p.getPixelY()>=0&&p.getPixelX()<surface->w&&p.getPixelY()<surface->h){
					drawPixel(surface,p,readPixel(border,pCero));
				}
			}else if(longitud<radiuos){
				if((p.getPixelX()>=0&&p.getPixelY()>=0&&p.getPixelX()<surface->w&&p.getPixelY()<surface->h)){
					drawPixel(surface,p,readPixel(back,pCero));	
				}
			}
		}
	}
	delete center;
	return surface;
}
void SketcherHelper::drawCircle(Position* center, int radiuos, Color* backColor, Color* borderColor)
{

	Uint32 rmask = 0xff000000;
	Uint32 gmask = 0x00ff0000;
	Uint32 bmask = 0x0000ff00;
	Uint32 amask = 0x00000000;
	SDL_Surface *back = SDL_CreateRGBSurface(SDL_SWSURFACE,1,1,this->screen->format->BitsPerPixel,amask,amask,amask,amask);
	SDL_Surface *border = SDL_CreateRGBSurface(SDL_SWSURFACE,1,1,this->screen->format->BitsPerPixel,amask,amask,amask,amask);

	Position pCero;
	pCero.setPixel(0,0);
	drawPixel(back,pCero,backColor);
	if(borderColor != NULL){
		drawPixel(border,pCero,borderColor);
	}
	double margin = radiuos * 0.04;

	for(int i = 0; i<2*(radiuos+margin);i++){
		for(int j = 0; j<2*(radiuos+margin);j++){
			Position p;
			p.setPixel(i+(center->getPixelX()-radiuos),j+(center->getPixelY()-radiuos));
			double longitud= calcDist(p,*center);
			if(radiuos+margin>=longitud && radiuos-margin<=longitud){
				if(borderColor!=NULL&&p.getPixelX()>=0&&p.getPixelY()>=0&&p.getPixelX()<this->screen->w&&p.getPixelY()<this->screen->h){
					drawPixel(this->screen,p,readPixel(border,pCero));
				}
			}else if(longitud<radiuos){
				if((p.getPixelX()>=0&&p.getPixelY()>=0&&p.getPixelX()<this->screen->w&&p.getPixelY()<this->screen->h)){
					drawPixel(this->screen,p,readPixel(back,pCero));	
				}
			}
		}
	}
}

void SketcherHelper::drawCircle(Position* center, int radiuos, Texture* backTexture, Color* borderColor){
	
    Uint32 rmask = 0xff000000;
	Uint32 gmask = 0x00ff0000;
	Uint32 bmask = 0x0000ff00;
	Uint32 amask = 0x00000000;
	SDL_Surface *border=SDL_CreateRGBSurface(SDL_SWSURFACE,1,1,this->screen->format->BitsPerPixel,amask,amask,amask,amask);

	Position pCeroBorder;
	pCeroBorder.setPixel(0,0);
	
	double margin=radiuos*0.04;
	if(borderColor==NULL){
		radiuos=radiuos+margin;
	}else{
		drawPixel(border,pCeroBorder,borderColor);
	}
	
	SDL_Surface *imagen;

	if(images[backTexture->getPath()]){
		imagen = images[backTexture->getPath().c_str()];
	}else{
		imagen = SDL_LoadBMP(backTexture->getPath().c_str());
		images[backTexture->getPath()] = imagen;
	}

	int width;
	int height;
	Position initial;
	if(imagen->w<imagen->h){
		width=2*radiuos+5;
		height=width*imagen->h/imagen->w+5;
		initial.setPixel(0,(height-2*radiuos)/2);
	}else{
		height=2*radiuos+5;
		width=height*imagen->w/imagen->h+5;
		initial.setPixel((width-2*radiuos)/2,0);
	}

	SDL_Surface * cuadrado=scaleSurface(imagen,width,height);

	Position pCero;
	for(register int i=0;i<2*(radiuos+margin);i++){
		for(register int j=0;j<2*(radiuos+margin);j++){
			Position p;
			p.setPixel(i+(center->getPixelX()-radiuos),j+(center->getPixelY()-radiuos));
			double longitud= calcDist(p,*center);
			if(radiuos+margin>=longitud && radiuos-margin<=longitud){
				if(borderColor!=NULL&&p.getPixelX()>=0&&p.getPixelY()>=0&&p.getPixelX()<this->screen->w&&p.getPixelY()<this->screen->h){
					drawPixel(this->screen,p,readPixel(border,pCeroBorder));
				}
			}else if(longitud<radiuos){
				pCero.setPixel(initial.getPixelX()+i,initial.getPixelY()+j);
				if((p.getPixelX()>=0&&p.getPixelY()>=0&&p.getPixelX()<this->screen->w&&p.getPixelY()<this->screen->h)&&
					pCero.getPixelX()>=0&&pCero.getPixelY()>=0&&pCero.getPixelX()<cuadrado->w&&pCero.getPixelY()<cuadrado->h){
					drawPixel(this->screen,p,readPixel(cuadrado,pCero));	
				}
			}
		}
	}
}


void SketcherHelper::drawSquareFromSurface(SDL_Surface* cuadrado,Position* position,double angle){

	Position* initialPosition=new Position();
	initialPosition->setPixel(position->getPixelX()+(cuadrado->h/2)*cos(pi*3/2+angle),
							  position->getPixelY()+(cuadrado->h/2)*sin(pi*3/2+angle));

	Position p;
	Position pCero;
	if(sin(angle)==0 || cos(angle)==0){
		 for(register int i=0;i<cuadrado->w;i++){
			for(register int j=0;j<cuadrado->h;j++){
				p.setPixel(i+initialPosition->getPixelX(),j+initialPosition->getPixelY());
				pCero.setPixel(i,j);
				drawPixel(this->screen,p,readPixel(cuadrado,pCero));				
			}
		}
	 }else{

		 int * alreadySettedPixels[1280];

		 for (register int i = 0; i < 1280; i++)
		 {
			 alreadySettedPixels[i] = new int[768];
			 for (register int j = 0; j < 768; j++)
			 {
				 alreadySettedPixels[i][j] = NULL;
			 }
		 }

		 int endX = cuadrado->w + initialPosition->getPixelX();
		 int endY = cuadrado->h + initialPosition->getPixelY();

		 for(register int i = initialPosition->getPixelX(); i < endX; i++){
			for(register int j = initialPosition->getPixelY(); j < endY; j++){

				p.setPixel(i,j);
				double initialAlfa = calcAngle(*(initialPosition),p);
				double longitud = calcDist(*(initialPosition),p);
				double anglePlusAlfa = angle + initialAlfa;
				
				Position rotated;
				rotated.setPixel(initialPosition->getPixelX()+longitud*cos(anglePlusAlfa),initialPosition->getPixelY()+longitud*sin(anglePlusAlfa));

				if(rotated.getPixelX() >= 0 && rotated.getPixelY() >= 0
							&&rotated.getPixelX() < this->screen->w
							&&rotated.getPixelY() < this->screen->h){
					
					pCero.setPixel(i-initialPosition->getPixelX(),j-initialPosition->getPixelY());

					Uint32 readedPixel = readPixel(cuadrado,pCero);

					drawPixel(this->screen,rotated,readedPixel);
					
					alreadySettedPixels[rotated.getPixelX()][rotated.getPixelY()] = 1;

					//fila anterior
					rotated.decreasePixelX();
					if(rotated.getPixelX() >=0){
						rotated.increasePixelY();
					
						if(rotated.getPixelY()<this->screen->h && rotated.getPixelY()>=0 &&
							alreadySettedPixels[rotated.getPixelX()][rotated.getPixelY()] == NULL){
							drawPixel(this->screen,rotated,readedPixel);
						}
						rotated.decreasePixelY();
					
						if(rotated.getPixelY()<this->screen->h && rotated.getPixelY()>=0 &&
							alreadySettedPixels[rotated.getPixelX()][rotated.getPixelY()]==NULL){
							drawPixel(this->screen,rotated,readedPixel);
						}
						rotated.decreasePixelY();
					
						if(rotated.getPixelY()<this->screen->h && rotated.getPixelY()>=0 &&
							alreadySettedPixels[rotated.getPixelX()][rotated.getPixelY()]==NULL){
							drawPixel(this->screen,rotated,readedPixel);
						}
						rotated.increasePixelY();
					}
					rotated.increasePixelX();
					//fila actual
					rotated.increasePixelX();
					rotated.increasePixelY();
					
					if(rotated.getPixelY()<this->screen->h && rotated.getPixelY()>=0 &&
						alreadySettedPixels[rotated.getPixelX()][rotated.getPixelY()]==NULL){
						drawPixel(this->screen,rotated,readedPixel);
					}
					rotated.decreasePixelY();
					rotated.decreasePixelY();
					
					if(rotated.getPixelY()<this->screen->h && rotated.getPixelY()>=0 &&
						alreadySettedPixels[rotated.getPixelX()][rotated.getPixelY()]==NULL){
						drawPixel(this->screen,rotated,readedPixel);
					}
					rotated.increasePixelY();
					rotated.decreasePixelX();
					//fila siguiente
					rotated.increasePixelX();
					if(rotated.getPixelX() < this->screen->w){
						rotated.increasePixelY();
						
						if(rotated.getPixelY()<this->screen->h && rotated.getPixelY()>=0 &&
							alreadySettedPixels[rotated.getPixelX()][rotated.getPixelY()]==NULL){
							drawPixel(this->screen,rotated,readedPixel);
						}
						rotated.decreasePixelY();
						
						if(rotated.getPixelY()<this->screen->h && rotated.getPixelY()>=0 &&
							alreadySettedPixels[rotated.getPixelX()][rotated.getPixelY()]==NULL){
							drawPixel(this->screen,rotated,readedPixel);
						}
						rotated.decreasePixelY();
						
						if(rotated.getPixelY()<this->screen->h && rotated.getPixelY()>=0 &&
							alreadySettedPixels[rotated.getPixelX()][rotated.getPixelY()]==NULL){
							drawPixel(this->screen,rotated,readedPixel);
						}
						rotated.increasePixelY();
					}
					rotated.decreasePixelX();								
				}

			}

		 }	

		 for (register int i = 0; i < 1280; i++){
			 delete [] alreadySettedPixels[i];
		 }
	 }
	 delete initialPosition;
}

void SketcherHelper::drawSquare(Position* position, int width, int height, double angle, Color* backColor, Color* borderColor)
{

	if(width==0 || height==0) return;
	Uint32 rmask=0xff000000;
	Uint32 gmask=0x00ff0000;
	Uint32 bmask=0x0000ff00;
	Uint32 amask=0x00000000;

	SDL_Surface *cuadrado=SDL_CreateRGBSurface(SDL_SWSURFACE,width,height,this->screen->format->BitsPerPixel,amask,amask,amask,amask);

	SDL_Rect dest;
	dest.w=width;
	dest.h=height;
	dest.x=0;
	dest.y=0;
	for(register int i=0;i<cuadrado->w;i++){
		for(register int j=0;j<cuadrado->h;j++){
			Position p;
			p.setPixel(i,j);
			drawPixel(cuadrado,p,backColor);
		}
	}
	//SDL_FillRect(cuadrado,&dest,SDL_MapRGB(this->screen->format,255,0,0));
	if(borderColor!=NULL){
		for(register int i=0;i<width;i++){
			Position p;
			p.setPixel(i,0);
			drawPixel(cuadrado,p,borderColor);
			p.setPixel(i,cuadrado->h-1);
			drawPixel(cuadrado,p,borderColor);
		}
		for(register int i=0;i<height;i++){
			Position p;
			p.setPixel(0,i);
			drawPixel(cuadrado,p,borderColor);
			p.setPixel(cuadrado->w-1,i);
			drawPixel(cuadrado,p,borderColor);
		}
	}
	drawSquareFromSurface(cuadrado,position,angle);
	
}

void SketcherHelper::drawSquare(Position* position, int width, int height, double angle, Texture* backTexture, Color* borderColor)
{	
	SDL_Rect dest;
	dest.w=width;
	dest.h=height;
	dest.x=0;
	dest.y=0;
	
	SDL_Surface *imagen;

	if(images[backTexture->getPath()]){
		imagen = images[backTexture->getPath().c_str()];
	}else{
		imagen = SDL_LoadBMP(backTexture->getPath().c_str());
		images[backTexture->getPath()] = imagen;
	}

	SDL_Surface * cuadrado=scaleSurface(imagen,width,height);
	if(borderColor!=NULL){
		for(int i=0;i<width;i++){
			Position p;
			p.setPixel(i,0);
			drawPixel(cuadrado,p,borderColor);
			p.setPixel(i,cuadrado->h-1);
			drawPixel(cuadrado,p,borderColor);
		}
		 for(int i=0;i<height;i++){
			Position p;
			p.setPixel(0,i);
			drawPixel(cuadrado,p,borderColor);
			p.setPixel(cuadrado->w-1,i);
			drawPixel(cuadrado,p,borderColor);
		}
	}
	drawSquareFromSurface(cuadrado,position,angle);
}



void SketcherHelper::drawLine(Position* fromPosition,Position* toPosition, Color* backColor, Color* borderColor){
	int b;
	float m;
	Position * aux = new Position();
	int minPixelY = min(fromPosition->getPixelY(), toPosition->getPixelY());
	int maxPixelY = max(fromPosition->getPixelY(), toPosition->getPixelY());
	int minPixelX = min(fromPosition->getPixelX(), toPosition->getPixelX());
	int maxPixelX = max(fromPosition->getPixelX(), toPosition->getPixelX());

	Position * leftPosition = fromPosition->getPixelX() == minPixelX ? fromPosition : toPosition;
	b = leftPosition->getPixelY(); // La ordenada al origen se considera corresponde al menor x.
	m = tan(GeometryHelper::getInstance()->getAngle(fromPosition,toPosition));

	if(fromPosition->getPixelX() == toPosition->getPixelX()) {
		for(int i = minPixelY ; i <= maxPixelY ; i++) {
			aux->setPixel(fromPosition->getPixelX(),i);
			if((aux->getPixelX()>=0&&aux->getPixelY()>=0&&aux->getPixelX()<this->screen->w&&aux->getPixelY()<this->screen->h))
				drawPixel(this->screen,*aux,borderColor);
		}
	}else {
		int y, x = minPixelX;
		int lastY = GeometryHelper::getInstance()->fx(x-minPixelX,m,b);
		for(x; x <= maxPixelX; x++) {
			y = GeometryHelper::getInstance()->fx(x-minPixelX,m,b);
			for(int yCorrect = min(y,lastY); yCorrect < max(y,lastY);yCorrect++ ) {
				aux->setPixel(x,yCorrect);
				if((aux->getPixelX()>=0&&aux->getPixelY()>=0&&aux->getPixelX()<this->screen->w&&aux->getPixelY()<this->screen->h))
					drawPixel(this->screen,*aux,borderColor);
			}
			aux->setPixel(x,y);
			if((aux->getPixelX()>=0&&aux->getPixelY()>=0&&aux->getPixelX()<this->screen->w&&aux->getPixelY()<this->screen->h))
				drawPixel(this->screen,*aux,borderColor);
			lastY = y;
		}
	}
	delete aux;
}

SDL_Surface *SketcherHelper::scaleSurface(SDL_Surface *Surface, Uint16 Width, Uint16 Height)
{
	if(!Surface || !Width || !Height)
		return 0;

	SDL_Surface *_ret = SDL_CreateRGBSurface(Surface->flags, Width, Height, Surface->format->BitsPerPixel,
		Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask, Surface->format->Amask);

	double  _stretch_factor_x = (static_cast<double>(Width)  / static_cast<double>(Surface->w)),
		_stretch_factor_y = (static_cast<double>(Height) / static_cast<double>(Surface->h));

	for(Sint32 y = 0; y < Surface->h; y++)
		for(Sint32 x = 0; x < Surface->w; x++)
			for(Sint32 o_y = 0; o_y < _stretch_factor_y; ++o_y)
				for(Sint32 o_x = 0; o_x < _stretch_factor_x; ++o_x){
					Position aux;
					aux.setPixel(static_cast<Sint32>(_stretch_factor_x * x) + o_x,
						         static_cast<Sint32>(_stretch_factor_y * y) + o_y);
					Position initial;
					initial.setPixel(x,y);
					drawPixel(_ret,aux,readPixel(Surface,initial));
				}

	return _ret;
}
inline double SketcherHelper::calcDist(Position from,Position to){
	register double distx=to.getPixelX()-from.getPixelX();
	register double disty=to.getPixelY()-from.getPixelY();
	return pow( pow (distx, 2)+pow (disty, 2),0.5);
}
inline double SketcherHelper::calcAngle(Position from,Position to){
	register double distx=to.getPixelX()-from.getPixelX();
	register double disty=to.getPixelY()-from.getPixelY();
	return (double)atan2(disty,distx);
}	


void SketcherHelper::drawPixel(SDL_Surface* target, Position position, Uint32 pixel){
	register int x=position.getPixelX();
	register int y=position.getPixelY();
	register int bpp = target->format->BytesPerPixel;
	/* Here p is the address to the pixel we want to set */
	Uint8 *p = (Uint8 *)target->pixels + y * target->pitch + x * bpp;

	switch(bpp) {
	case 1:
		*p = pixel;
		break;

	case 2:
		*(Uint16 *)p = pixel;
		break;

	case 3:
		if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
			p[0] = (pixel >> 16) & 0xff;
			p[1] = (pixel >> 8) & 0xff;
			p[2] = pixel & 0xff;
		} else {
			p[0] = pixel & 0xff;
			p[1] = (pixel >> 8) & 0xff;
			p[2] = (pixel >> 16) & 0xff;
		}
		break;

	case 4:
		*(Uint32 *)p = pixel;
		break;
	}

} 

Uint32  SketcherHelper::readPixel(SDL_Surface* source,  Position position){
	register int x=position.getPixelX();
	register int y=position.getPixelY();
	register int bpp = source->format->BytesPerPixel;
	/* Here p is the address to the pixel we want to retrieve */
	Uint8 *p = (Uint8 *)source->pixels + y * source->pitch + x * bpp;

	switch(bpp) {
	case 1:
		return *p;
		break;

	case 2:
		return *(Uint16 *)p;
		break;

	case 3:
		if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
			return p[0] << 16 | p[1] << 8 | p[2];
		else
			return p[0] | p[1] << 8 | p[2] << 16;
		break;

	case 4:
		return *(Uint32 *)p;
		break;

	default:
		return 0;       /* shouldn't happen, but avoids warnings */
	}

} 
void SketcherHelper::drawPixel(SDL_Surface *target, Position position, Color * color){
  register int x=position.getPixelX();
  register int y=position.getPixelY();
  Uint32 c = SDL_MapRGB(target->format, color->getR(), color->getG(), color->getB());
  switch (target->format->BytesPerPixel)
  {
    case 1: // 8-bpp
      {
        Uint8 *bufp;
        bufp = (Uint8 *)target->pixels + y*target->pitch + x;
        *bufp = c;
      }
      break;
    case 2: // 15-bpp or 16-bpp
      {
        Uint16 *bufp;
        bufp = (Uint16 *)target->pixels + y*target->pitch/2 + x;
        *bufp = c;
      }
      break;
    case 3: // 24-bpp mode, usually not used
      {
        Uint8 *bufp;
        bufp = (Uint8 *)target->pixels + y*target->pitch + x * 3;
        if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
        {
          bufp[0] = c;
          bufp[1] = c >> 8;
          bufp[2] = c >> 16;
        } else {
          bufp[2] = c;
          bufp[1] = c >> 8;
          bufp[0] = c >> 16;
        }
      }
      break;
    case 4: // 32-bpp
      {
        Uint32 *bufp;
        bufp = (Uint32 *)target->pixels + y*target->pitch/4 + x;
        *bufp = c;
      }
      break;
  }
} 

void SketcherHelper::show(){
	SDL_Flip(this->screen);
}

void SketcherHelper::setCoefs(float coeficienteX, float coeficienteY, float coeficiente, int initialX, int initialY, int pixelsHeight) {
	this->coeficienteX = coeficienteX;
	this->coeficienteY = coeficienteY;
	this->coeficiente = coeficiente;
	this->initialX = initialX;
	this->initialY = initialY;
	this->pixelsHeight = pixelsHeight;
}

Position* SketcherHelper::getPositionInPixels( Position * position ) {
	Position * posResult = new Position(position->getAxisX()*coeficiente-initialX,pixelsHeight - (position->getAxisY()*coeficiente-initialY));  
	posResult->setAxisX(position->getAxisX());
	posResult->setAxisY(position->getAxisY());
	return posResult;
}

Position* SketcherHelper::getPositionMeasurementUnit( Position * position ){
	return new Position((position->getAxisX()+initialX)/this->coeficiente,(pixelsHeight - position->getAxisY() + initialY) / coeficiente);
}

void SketcherHelper::drawTriangle( TriangularObstacle * triangle, Color * backGroundColor, Color * lineColor ){
Uint32 initialTicks = SDL_GetTicks();
	Position pixelToDraw;
	pixelToDraw.setPixel(0,0);
	list<Position*>::iterator iterEdge1;
	int i = 0;

	// Define el minimo rectangulo para copiar pixeles.
	int minPixelX = min(triangle->getP1()->getPixelX(),triangle->getP2()->getPixelX());
	minPixelX = min(minPixelX, triangle->getP3()->getPixelX());
	int minPixelY = min(triangle->getP1()->getPixelY(),triangle->getP2()->getPixelY());
	minPixelY = min(minPixelY, triangle->getP3()->getPixelY());	
	int maxPixelX = max(triangle->getP1()->getPixelX(),triangle->getP2()->getPixelX());
	maxPixelX = max(maxPixelX, triangle->getP3()->getPixelX());
	int maxPixelY = max(triangle->getP1()->getPixelY(),triangle->getP2()->getPixelY());
	maxPixelY = max(maxPixelY, triangle->getP3()->getPixelY());		

	Position * p = new Position();
	for(int i = minPixelX ; i<= maxPixelX ; i++) {
		for(int j = minPixelY ; j<= maxPixelY ; j++) {
			
			p->setPixel(i,j);
			int included = triangle->include(p);

			switch (included) {
				case 0:
					drawPixel(screen,*p,lineColor);
					//printf("Borde: (%i,%i)\n" ,i,j);
					break;
				case 1:
					drawPixel(screen,*p,backGroundColor);
					//printf("Interno: (%i,%i)\n" ,i,j);
					break;
			}
		}
	}
	delete p;

}

float SketcherHelper::getCoeficiente()
{
	return this->coeficiente;
}
void SketcherHelper::printText(Position* p,Color* c, string text )
{
	SDL_Surface *message = NULL; 
	string txt_toprint;
	
	
	/*---------------------Create the Render Text---------------------*/
	this->textColor.r=(Uint8) c->getR();
	this->textColor.g=(Uint8)c->getG();
	this->textColor.b=(Uint8)c->getB(); 
	txt_toprint.append(text);
	message=TTF_RenderText_Solid(font, txt_toprint.c_str() ,textColor);
	if (message==NULL)
		return;	
	
	/*--------------------Clean the Background-----------------------*/
	this->aux_rect->x=p->getPixelX(); //getAxisX()
	this->aux_rect->y=p->getAxisY();	
	clearBackground(p,text_x+100,text_y);
	SDL_BlitSurface(message, NULL, screen, this->aux_rect);
	
	text_x=message->w;
	text_y=message->h;



	/*-------------------Update the Main Surface---------------------*/
	if (SDL_Flip(screen)==-1)
		return;

	return;
}

bool SketcherHelper::containsCache(string key)
{
	return cache.find(key) != cache.end();
}

void SketcherHelper::addCachedCircle(string key, int radiuos, Texture* backTexture, Color* borderColor, int angle)
{
	SDL_Surface* image = loadImage(backTexture->getPath());
	SDL_Surface* scaled = scaleSurface(image, radiuos * 2, radiuos * 2);
	SDL_FreeSurface(image);
	SDL_Surface* circled = clipCircle(scaled);
	SDL_FreeSurface(scaled);
	cache[key] = rotateCircle(circled, angle);
}

void SketcherHelper::drawCachedCircle(string key, Position* position)
{
	SDL_Surface* circle = cache[key];
	if(circle != NULL)
	{
		int radious = circle->w / 2;
		SDL_Rect offset;
		offset.x = position->getPixelX() - radious;
		offset.y = position->getPixelY() - radious;
		SDL_BlitSurface(circle, NULL, this->screen, &offset);
	}
}

SDL_Surface* SketcherHelper::loadImage(string filename)
{
	SDL_Surface* image = SDL_LoadBMP(filename.c_str());
	if(image != NULL)
	{
		SDL_Surface* optimizedImage = SDL_DisplayFormat(image);
		SDL_FreeSurface(image);
		Uint32 colorKey = SDL_MapRGB(optimizedImage->format, 0xFF, 0xFF, 0xFF);
		SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorKey);
		return optimizedImage;
	}
	return NULL;
}

SDL_Surface* SketcherHelper::clipCircle(SDL_Surface* source)
{
	int diameter = 0;
	if(source->w < source->h)
	{
		diameter = source->w;
	}
	else
	{
		diameter = source->h;
	}
	int centerX = source->w / 2;
	int centerY = source->h / 2;

	SDL_Surface* result = NULL;
	if(source->flags & SDL_SRCCOLORKEY)
	{
		result = SDL_CreateRGBSurface(SDL_SWSURFACE, diameter, diameter, source->format->BitsPerPixel, source->format->Rmask, source->format->Gmask, source->format->Bmask, 0);
	}
	else
	{
		result = SDL_CreateRGBSurface(SDL_SWSURFACE, diameter, diameter, source->format->BitsPerPixel, source->format->Rmask, source->format->Gmask, source->format->Bmask, source->format->Amask);
	}
	
	Uint32 colorKey = SDL_MapRGB(result->format, 0xFF, 0xFF, 0xFF);
	SDL_SetColorKey(result, SDL_SRCCOLORKEY, colorKey);

	if(SDL_MUSTLOCK(source))
	{
		SDL_LockSurface(source);
	} 

	for(int y = 0; y < source->h; y++)
	{
		for(int x = 0; x < source->w; x++)
		{
			int distX = abs(x - centerX);
			int distY = abs(y - centerY);
			double dist = sqrt(double(distX * distX) + double(distY * distY));
			int px = x - ((source->w - diameter) / 2);
			int py = y - ((source->h - diameter) / 2);
			if((dist + 0.05) < double(diameter / 2))
			{
				setPixel(result, px, py, getPixel(source, x, y));
			}
			else if(px >= 0 && py >= 0 && px < diameter && py < diameter)
			{
				setPixel(result, px, py, colorKey);
			}
		}
	}

	if(SDL_MUSTLOCK(source))
	{
		SDL_UnlockSurface(source);
	}

	return result;
}

SDL_Surface* SketcherHelper::rotateCircle(SDL_Surface* source, float angle)
{
	int diameter = source->w;
	int centerX = diameter / 2;
	int centerY = diameter / 2;

	SDL_Surface* result = NULL;
	if(source->flags & SDL_SRCCOLORKEY)
	{
		result = SDL_CreateRGBSurface(SDL_SWSURFACE, diameter, diameter, source->format->BitsPerPixel, source->format->Rmask, source->format->Gmask, source->format->Bmask, 0);
	}
	else
	{
		result = SDL_CreateRGBSurface(SDL_SWSURFACE, diameter, diameter, source->format->BitsPerPixel, source->format->Rmask, source->format->Gmask, source->format->Bmask, source->format->Amask);
	}
	
	Uint32 colorKey = SDL_MapRGB(result->format, 0xFF, 0xFF, 0xFF);
	SDL_SetColorKey(result, SDL_SRCCOLORKEY, colorKey);

	if(SDL_MUSTLOCK(source))
	{
		SDL_LockSurface(source);
	} 

	for(int y = 0; y < source->h; y++)
	{
		for(int x = 0; x < source->w; x++)
		{
			int distX = abs(x - centerX);
			int distY = abs(y - centerY);
			double dist = sqrt(double(distX * distX) + double(distY * distY));
			if((dist + 0.05) < double(diameter / 2))
			{
				int tx = x - centerX;
				int ty = centerY - y;
				int rx = static_cast<int>((cos(angle * pi / 180) * float(tx)) - (sin(angle * pi / 180) * float(ty)));
				int ry = static_cast<int>((sin(angle * pi / 180) * float(tx)) + (cos(angle * pi / 180) * float(ty)));
				int nx = rx + centerX;
				int ny = centerY - ry;
				setPixel(result, nx, ny, getPixel(source, x, y));
			}
			else
			{
				int px = x - ((source->w - diameter) / 2);
				int py = y - ((source->h - diameter) / 2);
				if(px >= 0 && py >= 0 && px < diameter && py < diameter)
				{
					setPixel(result, px, py, colorKey);
					
				}
			}
		}
	}

	if(SDL_MUSTLOCK(source))
	{
		SDL_UnlockSurface(source);
	}

	return result;
}

void SketcherHelper::setPixel(SDL_Surface* target, Sint32 x, Sint32 y, Uint32 pixel)
{
	int bpp = target->format->BytesPerPixel;
	Uint8* p = (Uint8*)target->pixels + y * target->pitch + x * bpp;

	switch(bpp)
	{
		case 1:
			*p = pixel;
			break;
		case 2:
			*(Uint16*)p = pixel;
			break;
		case 3:
			if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
			{
				p[0] = (pixel >> 16) & 0xff;
				p[1] = (pixel >> 8) & 0xff;
				p[2] = pixel & 0xff;
			}
			else
			{
				p[0] = pixel & 0xff;
				p[1] = (pixel >> 8) & 0xff;
				p[2] = (pixel >> 16) & 0xff;
			}
			break;
		case 4:
			*(Uint32*)p = pixel;
			break;
	}
} 

Uint32 SketcherHelper::getPixel(SDL_Surface* source, Sint32 x, Sint32 y)
{
	int bpp = source->format->BytesPerPixel;
	Uint8* p = (Uint8*)source->pixels + y * source->pitch + x * bpp;

	switch(bpp) 
	{
		case 1:
			return *p;
			break;
		case 2:
			return *(Uint16*)p;
			break;
		case 3:
			if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
				return p[0] << 16 | p[1] << 8 | p[2];
			else
				return p[0] | p[1] << 8 | p[2] << 16;
			break;
		case 4:
			return *(Uint32*)p;
			break;
		default:
			return 0;       /* shouldn't happen, but avoids warnings */
	}
} 
